/***************************************************************************************
 * Copyright 2019 Infineon Technologies AG ( www.infineon.com ).                       *
 * All rights reserved.                                                                *
 *                                                                                     *
 * Licensed  Material-Property of Infineon Technologies AG.                            *
 * This software is made available solely pursuant to the terms of Infineon            *
 * Technologies AG agreement which governs its use. This code and the information      *
 * contained in it are proprietary and confidential to Infineon Technologies AG.       *
 * No person is allowed to copy, reprint, reproduce or publish any part of this code,  *
 * nor disclose its contents to others, nor make any use of it, nor allow or assist    *
 * others to make any use of it - unless by prior Written express authorization of     *
 * Infineon Technologies AG and then only to the extent authorized.                    *
 *                                                                                     *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,            *
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,           *
 * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED.  IN NO       *
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,     *
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,                 *
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;         *
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY             *
 * WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR            *
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF              *
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                          *
 *                                                                                     *
 ***************************************************************************************/
#include <stdio.h>

#include "auths_api.h"
#include "auths_config.h"
#include "auths_status.h"
#include "crypto_lib.h"
#include "gpo.h"
#include "i2c_bus_command.h"
#include "helper.h"

extern AuthS_Capability auths_capability;
uint16_t mcu_get_gpo_level(uint8_t *gpo_level);


extern uint16_t g_DevAddr;

#define I2C_TEST_CODE 0
#define SWI_TEST_CODE 1

/**
* @brief Get device GPO output level
* @param gpo_level GPO level read using the MCU
*/
uint16_t mcu_get_gpo_level(uint8_t *gpo_level)
{    
 //todo System porting required: implements platform GPIO, if required.
	gpo_level = NULL;

    return AUTHS_SUCCESS;
}

/**
* @brief Test various state of GPO output
*/
void test_gpo()
{
	uint8_t ub_data;
	uint8_t mcu_gpio_status=0;
	GPO_status gpo_config;
	uint16_t ret;
	
	// Authenticate S get GPO level
	ret = auths_get_gpo_level(&ub_data);
	if(APP_GPO_SUCCESS != ret){
		PRINT("Get Authenticate S GPO status failed. 0x%x", ret);
	}
	PRINT("Authenticate S GPO Status: %d\r\n",ub_data);

	// MCU get GPO level
	ret = mcu_get_gpo_level(&mcu_gpio_status);
	if(APP_GPO_SUCCESS != ret){
		PRINT("Get MCU GPO status failed. 0x%x", ret);
	}	
	PRINT("MCU GPO Status: %d\r\n", mcu_gpio_status);

	if(mcu_gpio_status != ub_data){
		PRINT("Mismatch: MCU GPO level is different from Authenticate S reported GPO status. 0x%x\r\n", ret);
	}
	
	// Set Authenticate S GPO to Strong high
	PRINT("Set Authenticate S GPO to strong high\r\n");
	ret = auths_set_gpo_config(strongHigh);
	ret = auths_get_gpo_config(&gpo_config);
	if(APP_GPO_SUCCESS != ret){
		PRINT("Error: Unable to get Authenticate S GPO status: 0x%x\r\n", ret);
	}
	
	// MCU get GPO level
	ret = mcu_get_gpo_level(&mcu_gpio_status);
	if(APP_GPO_SUCCESS != ret){
		PRINT("Get MCU GPO status failed. 0x%x", ret);
	}	
	PRINT("MCU GPO Status: %d\r\n", mcu_gpio_status);
	if(mcu_gpio_status == 0){
		PRINT("Mismatch: MCU GPO level is low not strong high.\r\n");
	}

    // Set GPO Strong low
 	PRINT("Set Authenticate S GPO to strong low\r\n");
	ret = auths_set_gpo_config(strongLow);
	ret = auths_get_gpo_config(&gpo_config);
	if(APP_GPO_SUCCESS != ret){
		PRINT("Read Authenticate S GPO level failed. 0x%x\r\n", ret);
	}

	// MCU get GPO level
	ret = mcu_get_gpo_level(&mcu_gpio_status);
	if(APP_GPO_SUCCESS != ret){
		PRINT("Get MCU GPO status failed. 0x%x", ret);
	}	
	PRINT("MCU GPO Status: %d\r\n", mcu_gpio_status);
	if(mcu_gpio_status == 1){
		PRINT("Mismatch: MCU GPO level is high not Strong low.\r\n");
	}
	
	// Set GPO Weak high
	PRINT("Set Authenticate S GPO to weak high\r\n");
	ret = auths_set_gpo_config(weakHigh);
	ret = auths_get_gpo_config(&gpo_config);
	if(AUTHS_SUCCESS != ret){
		PRINT("Authenticate S GPO set level failed. 0x%x\r\n", ret);
	}

	// MCU get GPO level
	ret = mcu_get_gpo_level(&mcu_gpio_status);
	if(APP_GPO_SUCCESS != ret){
		PRINT("Get MCU GPO status failed. 0x%x", ret);
	}	
	PRINT("MCU GPO Status: %d\r\n", mcu_gpio_status);
	if(mcu_gpio_status == 0){
		PRINT("Mismatch: MCU GPO level is low not weak high.\r\n");
	}

	// Set GPO weak low
	PRINT("Set Authenticate S GPO to weak low\r\n");
	ret = auths_set_gpo_config(weakLow);
	ret = auths_get_gpo_config(&gpo_config);
	if(APP_GPO_SUCCESS != ret){
		PRINT("Authenticate S get GPO failed. 0x%x\r\n", ret);
	}

	// MCU get GPO level
	ret = mcu_get_gpo_level(&mcu_gpio_status);
	if(APP_GPO_SUCCESS != ret){
		PRINT("Get MCU GPO status failed. 0x%x", ret);
	}	
	PRINT("MCU GPO Status: %d\r\n", mcu_gpio_status);
	if(mcu_gpio_status == 1){
		PRINT("Mismatch: MCU GPO level is high not weak low.\r\n");
	}

}

/**
* @brief Test GPO trigger from low to high when Auto Host Auth GPO trigger is enabled.
*/			
void ha_set_gpo_high(){

	uint8_t ub_data_1;
	uint16_t ret;

	if(auths_capability.device_attribute.gpo_trigger_authentication != supported){
		PRINT("Error: GPO host authentication trigger not supported.\r\n");
		return;
	}
	
	// HA trigger GPO high
	ret = auths_get_gpo_level(&ub_data_1);
	if(APP_GPO_SUCCESS != ret){
		PRINT("Authenticate S get GPO level failed.\r\n");
	}
	PRINT("GPO level: %d\r\n",ub_data_1);

	if(ub_data_1 == 1){
		PRINT("Set GPO low.\r\n");
		ret = auths_set_gpo_config(strongLow);
		ret = auths_get_gpo_level(&ub_data_1);
		if(APP_GPO_SUCCESS != ret){
			PRINT("Authenticate S get GPO level failed.\r\n");
		}
		PRINT("GPO level: %d\r\n",ub_data_1);
		if(ub_data_1 == 1){
			PRINT("Wrong: GPO level is high.\r\n");
			return;
		}
  }

#if (HOST_AUTHENTICATION_FEATURE_SUPPORTED == 1)
		PRINT("Run Host Auth.\r\n");
		ret = auths_exe_host_authentication();
		if (APP_HA_SUCCESS != ret) {
			PRINT_C(RED, "Host Authentication failed.\r\n");
		} else {
			PRINT("Host Authenticated\r\n");
		}
#endif
        delay_ms(1);
		ret = auths_get_gpo_level(&ub_data_1);
		if(APP_GPO_SUCCESS != ret){
			PRINT("Authenticate S get GPO level failed.\r\n");
		}

		PRINT("GPO level: %d\r\n",ub_data_1);
		if(ub_data_1 == 0){
			PRINT("Wrong: GPO level is low.\r\n");
		}
}

/**
* @brief Test GPO trigger from low to high when Auto LSC2 GPO trigger is enabled.
*/	
void lsc2_set_gpo_high(){

	uint8_t ub_data_1;
	uint16_t ret;
	uint32_t lsc2;
	uint16_t count=1024;

	if(auths_capability.device_attribute.gpo_trigger_lsc2 != supported){
		PRINT("Error: GPO LSC trigger not supported.\r\n");
		return;
	}

    // LSC2 reaches 0 trigger GPO high
	PRINT("Check GPO low.\r\n");
	ret = auths_get_gpo_level(&ub_data_1);
	if(APP_GPO_SUCCESS != ret){
		PRINT("Error: Unable to get GPO level 0x%x.\r\n", ret);
	}
	
	PRINT("GPO level: %d\r\n", ub_data_1);
	if(ub_data_1 == 1){
		PRINT("Set GPO low.\r\n");
		ret = auths_set_gpo_config(strongLow);
		ret = auths_get_gpo_level(&ub_data_1);
		if(APP_GPO_SUCCESS != ret){
			PRINT("Error: Unable to read device level 0x%x.\r\n", ret);
		}

		PRINT("GPO level: %d\r\n",ub_data_1);
		if(ub_data_1 == 1){
			PRINT("Wrong: GPO level is high.\r\n");
			return;
		}
	}

	ret = auths_set_lsc_value(1, 3000);
	if(APP_LSC_SUCCESS != ret){
		PRINT("Error: Unable to write to LSC2 0x%x\r\n", ret);
		return;
	}

	// decrease lsc2 to 0
	ret = auths_get_lsc_value(1, &lsc2);
	if(APP_LSC_SUCCESS != ret){
		PRINT("Error: Unable to read LSC2 0x%x\r\n", ret);
		return;
	}
	PRINT("LSC2 = 0x%.8X\r\n",lsc2);
	do{
		ret = auths_set_lsc_decvalue(1, count);
		if(APP_LSC_SUCCESS != ret){			
			PRINT("Error: Unable to decrease LSC2 0x%x\r\n", ret);
			return;
		}
		delay_ms(7);
		ret = auths_get_lsc_value(1,&lsc2);
		if(APP_LSC_SUCCESS != ret){
		PRINT("Error: Unable to read LSC2 0x%x\r\n", ret);
		return;
		}
		PRINT("LSC2 = 0x%.8X\r\n",lsc2);
		}while(lsc2 > 0);
				
        delay_ms(1);
		ret = auths_get_gpo_level(&ub_data_1);
		if(APP_GPO_SUCCESS != ret){
			PRINT("Error: Unable to get device GPO level 0x%x\r\n", ret);
		}
			PRINT("GPO level: %d\r\n",ub_data_1);
			if(ub_data_1 == 0){
				PRINT("Error: GPO level is Low.\r\n");
			}
		}
